package net.cyndeline.events.gameplay

import net.cyndeline.math.Rational
import com.escalatesoft.subcut.inject.BindingModule
import com.escalatesoft.subcut.inject.Injectable
import net.cyndeline.subcut.BindingKeys.DefaultTimeTick
import net.cyndeline.entitySystem.Event

/**
 * This event is sent to every unit with a time component, and represents the
 * smallest time measurement in the game, a.k.a one tick. Upon being received,
 * the tick value is subtracted from the component.
 * 
 * This is the event that should be modified to implement time-adjusting
 * effects such as haste and slow. 
 * 
 * Note that one turn has multiple ticks in it. To ensure consistency with
 * future alterations of the ticks/turn ratio, only modify it based on
 * percentages of the original value, and not absolute values.
 */
class TimeTick(implicit val bindingModule: BindingModule) extends TimeTickEvent with Injectable {
  private var value: Rational = injectOptional [Rational](DefaultTimeTick) getOrElse { new Rational(1) }
  private var modified = value
  
  override def time = value
  
  override def time_=(newTime: Rational) {
    value = newTime
    modified = value
  }
  
  override def modify(amount: Rational) {
    modified = modified + amount 
  }
  
  override def finalAmount = modified
  
  override def copy = {
    val copy = new TimeTick()
    copy.time = finalAmount
    copy
  }
  
  override def +(other: Event) = other match {
    case tt: TimeTick => {
      val combined = new TimeTick()
      combined.time = (finalAmount + tt.finalAmount)
      combined
    }
    case _ => copy
  }
}

trait TimeTickEvent extends Event {
  
  /** The amount to be subtracted from an entity's time amount. */
  def time: Rational
  
  /** Sets a new time value. Only use this when creating copies etc. To
   *  modify the time value, use modify(). Resets the modified value to
   *  the new time.
   */
  def time_=(newTime: Rational)
  
  /**
   * Modifies the time by some value (use negative values to decrease) by
   * adding the amount to the current value.
   * The modification will be separate from the original tick amount, which can
   * always be retrieved using the time method. When the event is being
   * processed, the final amount will receive all modifications.
   * @param amount Value to increase or decrease the entitys time by.
   */
  def modify(amount: Rational)
  
  /** Returns the final time after having been modified. */
  def finalAmount: Rational
}